using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace WindowsApplication1
{
    public enum ContextMode
    {
        /// <summary>
        /// dropDownContent closed after singl click on it's child control
        /// </summary>
        SingleSelect,
        /// <summary>
        /// dropDownContent closed after lost focus
        /// </summary>
        MultiSelect,
        /// <summary>
        /// dropDownContent closed as soon as mouse moved out of the dropdown parent
        /// </summary>
        ToolTip
    }

    public class DropDownContainer:Form
    {
        private Control _dropDownContent;
        private ContextMode _contextMode;
        private Rectangle _activeRect;
        private bool _focusOnOpen;
        private bool _resizable = false;

        public event EventHandler DropDownClosed;
        public event EventHandler DropDownOpening;

        public bool Resizable
        {
            get { return _resizable; }
            set { _resizable = value; }
        }

        public Control DropDownContent
        {
            get { return _dropDownContent; }
            set
            {
                if (_dropDownContent != null)
                {
                    this.Controls.Remove(_dropDownContent);
                }
                _dropDownContent = value;
                if (_dropDownContent != null)
                {
                    base.SuspendLayout();
                    _dropDownContent.Dock = DockStyle.Fill;
                    this.Controls.Add(_dropDownContent);
                    foreach (Control ctrl in _dropDownContent.Controls)
                    {
                        ctrl.MouseClick += ctrl_MouseClick;
                        ctrl.MouseEnter += ctrl_MouseEnter;
                        ctrl.KeyDown += ctrl_KeyDown;
                    }

                    _dropDownContent.MouseClick += ctrl_MouseClick;
                    _dropDownContent.MouseEnter += ctrl_MouseEnter;
                    _dropDownContent.KeyDown += ctrl_KeyDown;
                    base.ResumeLayout(false);
                }
            }
        }

        public bool FocusOnOpen
        {
            get { return _focusOnOpen; }
            set { _focusOnOpen = value; }
        }

        public ContextMode ContextMode
        {
            get
            {
                return _contextMode;
            }
            set
            {
                _contextMode = value;
            }
        }

        public new FormBorderStyle FormBorderStyle
        {
            get { return base.FormBorderStyle; }
            set { return; }
        }

        Color _borderColor = Color.Black;
        public System.Drawing.Color BorderColor
        {
            get { return _borderColor; }
            set { _borderColor = value; }
        }

        public int _borderWidth;
        public int BorderWidth
        {
            get { return _borderWidth; }
            set { _borderWidth = value; }
        }

        public new Padding Padding
        {
            get { return base.Padding; }
            set { return; }
        }

        public int DropDownHeight
        {
            get { return Height; }
            set { Height = value; }
        }

        public int DropDownWidth
        {
            get { return Width; }
            set { Width = value; }
        }

        public DropDownContainer()
        {
            this.ControlBox = false;
            this.MinimizeBox = false;
            base.FormBorderStyle = FormBorderStyle.None;
            base.Padding = new Padding(1);
            base.StartPosition = FormStartPosition.Manual;
            _activeRect = Rectangle.Empty;
            base.ShowInTaskbar = false;
        }

        void ctrl_MouseClick(object sender, MouseEventArgs e)
        {
            if (_contextMode == ContextMode.SingleSelect)
            {
                if (e.Button == MouseButtons.Left)
                    this.Hide();
            }
        }

        void ctrl_MouseEnter(object sender, EventArgs e)
        {
            if (_contextMode == ContextMode.ToolTip)
            {
                this.Hide();
            }
        }

        void ctrl_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                // Enact selection.
                if (_contextMode == ContextMode.SingleSelect)
                {
                    this.Hide();
                }
                e.Handled = true;

            }
            else if (e.KeyCode == Keys.Escape)
            {
                // Cancel selection.
                this.Hide();
                e.Handled = true;

            }

            // If no Enter or Esc keys presses, let the base class handle it.
            base.OnKeyDown(e);
        }

        /// <summary>
        /// show the dropdown content as the control's context
        /// </summary>
        /// <param name="control"></param>
        public void Show(Control control)
        {
            if (control == null)
                throw new ArgumentNullException("control shoul not be null!");
            _activeRect = control.RectangleToScreen(control.ClientRectangle);
            CalcLocation();

            if (!base.Visible)
            {
                base.Show(control);
            }            
        }

        /// <summary>
        /// show the drop content as if a control occupy the rect area
        /// usually serve as screen tip
        /// </summary>
        /// <param name="rect">active rect, in screen coordiante</param>
        public void Show(Rectangle rect,IWin32Window owner)
        {
            _activeRect = rect;
            CalcLocation();
            if (!base.Visible)
            {
                base.Show(owner);
            }            
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (base.Visible)
            {
                if (_focusOnOpen)
                {
                    _dropDownContent.Focus();
                }
                if (DropDownOpening != null)
                {
                    DropDownOpening(this, e);
                }
            }
            else
            {
                if (DropDownClosed != null)
                {
                    DropDownClosed(this, e);
                }
            }
        }

        protected override void OnDeactivate(EventArgs e)
        {
            base.OnDeactivate(e);
            this.Hide();
        }

        private void CalcLocation()
        {
            if (_activeRect != Rectangle.Empty)
            {
                Point location = new Point(_activeRect.Left, _activeRect.Bottom);
                Rectangle screenRect = (Screen.FromRectangle(_activeRect)).WorkingArea;

                if (location.X + Size.Width > (screenRect.Left + screenRect.Width))
                {
                    location.X = (screenRect.Left + screenRect.Width) - Size.Width;
                }

                if (location.Y + Size.Height > (screenRect.Top + screenRect.Height))
                {
                    location.Y -= Size.Height + _activeRect.Height;
                }
                this.Location = location;
            }
        }
    }
}
